package com.xiaominge.utils.wordUtils.wordOutputUtils.wordMerge;

import com.xiaominge.exception.ParameterRuntimeException;
import com.xiaominge.utils.wordUtils.wordOutputUtils.wordOut.footUtils.CreateFootUtils;
import com.xiaominge.utils.wordUtils.wordOutputUtils.wordOut.headerUtils.CreateHeaderUtils;
import com.xiaominge.utils.wordUtils.wordOutputUtils.wordOut.wordBean.FootBeans.FootPageBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.BreakType;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: case_system_parent
 * @description: word合并工具类
 * @author: Administrator
 * @create: 2020-02-17 13:07
 **/

/**
 * @author: Max
 * @Date: 2018/6/8
 * @name: 多个word文件合并，采用poi实现,兼容图片的迁移
 * @Description:
 */
@Slf4j
public class WordMergeDocxUtils {


    public static void main(String[] args) {

        File first = new File("D:\\idea-workspace\\hzf_admin\\/statis_word_temp/领导版--执法汇总报告_基本信息-2022年06月13日 14时50分24秒.docx");


        File next1 = new File("D:\\idea-workspace\\hzf_admin\\/statis_word_temp/table-1-2022年06月13日 14时50分24秒.docx");
        File next2 = new File("D:\\idea-workspace\\hzf_admin\\/statis_word_temp/table-2-2022年06月13日 14时50分24秒.docx");
        File next3 = new File("D:\\idea-workspace\\hzf_admin\\/statis_word_temp/table-3-2022年06月13日 14时50分24秒.docx");

        WordMergeDocxUtils wordMergeDocxUtils = new WordMergeDocxUtils();
      /*  try {
            wordMergeDocxUtils.mergeWord(first, next, new FileOutputStream(new File("D:/桌面/test11.docx")), true);

        } catch (Exception e) {
            e.printStackTrace();
        }
*/

        MergeDocxBean mergeDocxBean = new MergeDocxBean(first, new FootPageBean("第", "页,共", "页", null));
        mergeDocxBean.addNext(next1, true);
        mergeDocxBean.addNext(next2, true);
        mergeDocxBean.addNext(next3, true);

        try {
            wordMergeDocxUtils.mergeWord(mergeDocxBean, new FileOutputStream(new File("D:/桌面/test11.docx")));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        } catch (XmlException e) {
            e.printStackTrace();
        }


    }

    /**
     * @param firstDocFile   第一个文件
     * @param appendDocFiles 追加的问价  追加顺序 是list 的顺序
     * @param savePath       保存的文件地址
     * @param saveFileName   保存的文件名
     * @param isPageAppend   是否分页追加  默认false--文本不分页追加
     */
    public void mergeWord(File firstDocFile, List<File> appendDocFiles,
                          String savePath, String saveFileName, boolean isPageAppend) throws IOException, InvalidFormatException, XmlException {
        if (!saveFileName.endsWith(".docx") && !saveFileName.endsWith(".DOCX")) {
            saveFileName += ".docx";
        }
        if (!savePath.endsWith("/")) {
            savePath += "/";
        }
        MergeDocxBean mergeDocxBean = new MergeDocxBean(firstDocFile, null);
        for (File appendDocFile : appendDocFiles) {
            mergeDocxBean.addNext(appendDocFile, isPageAppend);
        }
        mergeWord(mergeDocxBean, new FileOutputStream(savePath + saveFileName));
    }


    /**
     * @param firstDocFile   第一个文件
     * @param appendDocFiles 追加的问价  追加顺序 是list 的顺序
     * @param outputStream   返回的流
     * @param isPageAppend   是否分页追加  默认false--文本不分页追加
     *                       //设置分页符---当刚好一页数据时，会导致出现空白页，后面出现分页符导致格式有一点差异
     */
    public void mergeWord(File firstDocFile, List<File> appendDocFiles, OutputStream outputStream, boolean isPageAppend) throws IOException, InvalidFormatException, XmlException {
        MergeDocxBean mergeDocxBean = new MergeDocxBean(firstDocFile, null);
        for (File appendDocFile : appendDocFiles) {
            mergeDocxBean.addNext(appendDocFile, isPageAppend);
        }
        mergeWord(mergeDocxBean, outputStream);
    }


    public void mergeWord(MergeDocxBean mergeDocxBean, String savePath, String saveFileName) throws IOException, InvalidFormatException, XmlException {
        if (!saveFileName.endsWith(".docx") && !saveFileName.endsWith(".DOCX")) {
            saveFileName += ".docx";
        }
        if (!savePath.endsWith("/")) {
            savePath += "/";
        }
        mergeWord(mergeDocxBean, new FileOutputStream(savePath + saveFileName));
    }


    public void mergeWord(MergeDocxBean mergeDocxBean, OutputStream outputStream) throws IOException, InvalidFormatException, XmlException {
        //判断文件结尾是不是docx
        File firstDocxFile = mergeDocxBean.getFirstDocxFile();
        if (!".docx".equalsIgnoreCase(mergeDocxBean.getFirstDocxFile().getName().substring(firstDocxFile.getName().indexOf(".")))) {
            log.error("第一个文件格式错误,暂时只能处理docx格式文件");
            throw new RuntimeException("第一个文件格式错误,暂时只能处理docx格式文件");
        }
        XWPFDocument firstDocument = new XWPFDocument(new FileInputStream(firstDocxFile));

        List<MergeDocxBean.nextDocxBean> nextDocxBeanList = mergeDocxBean.getNextDocxBeanList();
        if (nextDocxBeanList != null && !nextDocxBeanList.isEmpty()) {
            int size = nextDocxBeanList.size();
            for (int i = 0; i < size; i++) {
                MergeDocxBean.nextDocxBean nextDocxBean = nextDocxBeanList.get(i);
                File appendDocFiles = nextDocxBean.getNextDocxFile();
                if (!".docx".equalsIgnoreCase(appendDocFiles.getName().substring(appendDocFiles.getName().indexOf(".")))) {
                    log.error("第一个文件格式错误,暂时只能处理docx格式文件");
                    throw new RuntimeException("追加文件的第" + i + "个文件格式错误,暂时只能处理docx格式文件");
                }
                XWPFDocument nextDocument = new XWPFDocument(new FileInputStream(appendDocFiles));

                if (nextDocxBean.isPageAppend()) {
                    firstDocument.createParagraph().createRun().addBreak(BreakType.PAGE); //强制分页
                }
                appendBody(firstDocument, nextDocument);
            }
        }
        //最后判断是否添加页眉 页脚
        String headerContext = mergeDocxBean.getHeaderContext();
        if (StringUtils.isNotBlank(headerContext)) {
            try {
                CreateHeaderUtils.createHeader(firstDocument, mergeDocxBean.getHeaderFontBean(), headerContext, null);
            } catch (Exception e) {
                e.printStackTrace();
                ParameterRuntimeException.throwException("添加页眉失败");
            }
        }
        if (mergeDocxBean.isAddFoot()) {
            CreateFootUtils.createFooter(firstDocument, mergeDocxBean.getFootPageFontBean(), mergeDocxBean.getFootContentList(), mergeDocxBean.getFootPageBean());
        }
        firstDocument.write(outputStream);
        //first.close();
        outputStream.close();
    }


    public void appendBody(XWPFDocument src, XWPFDocument append) throws InvalidFormatException, XmlException {
        CTBody src1Body = src.getDocument().getBody();
        CTBody src2Body = append.getDocument().getBody();

        List<XWPFPictureData> allPictures = append.getAllPictures();
        // 记录图片合并前及合并后的ID
        Map<String, String> map = new HashMap();
        for (XWPFPictureData picture : allPictures) {
            String before = append.getRelationId(picture);
            //将原文档中的图片加入到目标文档中
            String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
            map.put(before, after);
        }
        appendBody(src1Body, src2Body, map);
    }

    private void appendBody(CTBody src, CTBody append, Map<String, String> map) throws XmlException {
        XmlOptions optionsOuter = new XmlOptions();
        optionsOuter.setSaveOuter();
        String appendString = append.xmlText(optionsOuter);

        String srcString = src.xmlText();

        //   srcString = srcString.replaceAll("<w:p><w:r><w:br w:type=\"page\"/></w:r></w:p>", "").replaceAll("<w:r><w:br w:type=\"page\"/></w:r>", "");

        //防止合并出错  页脚问题
        String rgex = "<[\\s]*?w:sectPr[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?w:sectPr[\\s]*?>";
        appendString = appendString.replaceAll(rgex, "");


        String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
        String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
        String sufix = srcString.substring(srcString.lastIndexOf("<"));

        String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));

        if (map != null && !map.isEmpty()) {
            //对xml字符串中图片ID进行替换
            for (Map.Entry<String, String> set : map.entrySet()) {
                addPart = addPart.replace(set.getKey(), set.getValue());
            }
        }
        //将两个文档的xml内容进行拼接
        CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);
        src.set(makeBody);
    }


}
